<template>
  <div id="webgl-container" ref="containerRef" class="webgl-container">
    <canvas id="webgl" class="webgl"/>
  </div>
</template>

<script setup>
import * as THREE from 'three'
import { ref, onMounted, onUnmounted, shallowRef } from 'vue'

import { useThree } from '@/hooks/use-three-hook.js'

const containerRef = ref(null)
const { scene, camera, addAnimationCallback, gui } = useThree()

// 雨的参数
const rainParams = shallowRef({
  count: 50000,
  speed: 1.0,
  size: 5,
  wind: 2,
  turbulence: 0.1,
  intensity: 1.0, // 雨的强度 (0.0 - 1.0)
  type: '中雨' // 雨的类型
})

const textureLoader = new THREE.TextureLoader()
const particleTexture = textureLoader.load('/textures/particles/raindrop-1.png')
particleTexture.colorSpace = THREE.SRGBColorSpace

// 雨滴粒子系统
let rainParticles = null
let rainGeometry = null

// 创建基于着色器的雨滴
const createRain = () => {
  const count = rainParams.value.count

  rainGeometry = new THREE.BufferGeometry()

  const positions = new Float32Array(count * 3)
  const uvCoords = new Float32Array(count * 2)
  const randoms = new Float32Array(count)

  for (let i = 0; i < count; i++) {
    const i3 = i * 3
    const i2 = i * 2

    // 随机位置
    positions[i3] = (Math.random() - 0.5) * 100 // x
    positions[i3 + 1] = Math.random() * 50 + 10 // y
    positions[i3 + 2] = (Math.random() - 0.5) * 100 // z

    // UV坐标
    uvCoords[i2] = Math.random()
    uvCoords[i2 + 1] = Math.random()

    // 随机因子
    randoms[i] = Math.random()
  }

  rainGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
  rainGeometry.setAttribute('particleUv', new THREE.BufferAttribute(uvCoords, 2))
  rainGeometry.setAttribute('random', new THREE.BufferAttribute(randoms, 1))

  // 创建着色器材质
  const rainMaterial = new THREE.ShaderMaterial({
    uniforms: {
      uTime: { value: 0 },
      uTexture: { value: particleTexture },
      uSize: { value: rainParams.value.size },
      uSpeed: { value: rainParams.value.speed },
      uWind: { value: rainParams.value.wind },
      uTurbulence: { value: rainParams.value.turbulence },
      uIntensity: { value: rainParams.value.intensity },
      uResolution: { value: new THREE.Vector2() }
    },
    vertexShader: `
      uniform float uTime;
      uniform float uSize;
      uniform float uSpeed;
      uniform float uWind;
      uniform float uTurbulence;
      uniform float uIntensity;
      
      attribute vec2 particleUv;
      attribute float random;
      
      varying vec2 vUv;
      varying float vAlpha;
      
      void main() {
        vUv = particleUv;

        vec3 pos = position;
        
        // 根据随机因子计算不同的下落速度
        float speedFactor = mix(0.5, 1.5, random);
        float fallSpeed = uSpeed * speedFactor;
        
        // 计算下落
        pos.y -= uTime * fallSpeed;
        
        // 添加风的影响
        pos.x += sin(uTime * 0.5 + pos.z * 0.1) * uWind;
        
        // 添加湍流效果
        pos.x += sin(uTime * 2.0 + pos.y * 0.2) * uTurbulence;
        pos.z += cos(uTime * 1.5 + pos.y * 0.15) * uTurbulence;
        
        // 循环效果 - 当雨滴落到地面以下时，重新设置到顶部
        if (pos.y < -10.0) {
          pos.y = 40.0 + mod(pos.y, 50.0);
          pos.x = (random - 0.5) * 100.0;
          pos.z = (random - 0.5) * 100.0;
        }
        
        // 根据强度调整透明度
        vAlpha = mix(0.0, 1.0, uIntensity);
        if (pos.y > 35.0) {
          vAlpha *= 1.0 - (pos.y - 35.0) / 5.0; // 顶部淡出
        }
        
        vec4 modelPosition = modelMatrix * vec4(pos, 1.0);
        vec4 viewPosition = viewMatrix * modelPosition;
        vec4 projectedPosition = projectionMatrix * viewPosition;
        
        gl_Position = projectedPosition;
        gl_PointSize = uSize * 100.0 / -viewPosition.z;
      }
    `,
    fragmentShader: `
      uniform sampler2D uTexture;
      
      varying vec2 vUv;
      varying float vAlpha;
      
      void main() {
        vec4 textureColor = texture2D(uTexture, vUv);
        if (textureColor.a < 0.1) discard;
        
        gl_FragColor = vec4(0.5, 0.5, 1.0, textureColor.a * vAlpha);
      }
    `,
    transparent: true,
    blending: THREE.AdditiveBlending,
    depthWrite: false
  })

  // 设置分辨率
  if (containerRef.value) {
    const { clientWidth, clientHeight } = containerRef.value
    rainMaterial.uniforms.uResolution.value.set(clientWidth, clientHeight)
  }

  // 创建粒子系统
  rainParticles = new THREE.Points(rainGeometry, rainMaterial)
  scene.value.add(rainParticles)
}

// 更新雨滴动画
const updateRain = (deltaTime, elapsedTime) => {
  if (rainParticles && rainParticles.material) {
    rainParticles.material.uniforms.uTime.value = elapsedTime
  }
}

// 动态调整雨的强度
const setRainIntensity = (intensity) => {
  if (rainParticles && rainParticles.material) {
    rainParticles.material.uniforms.uIntensity.value = intensity

    // 根据强度调整其他参数
    rainParticles.material.uniforms.uSpeed.value = 0.5 + intensity * 2.0
    rainParticles.material.uniforms.uSize.value = 0.05 + intensity * 0.15
    rainParticles.material.uniforms.uWind.value = intensity * 2.0
  }
}

// 预设的雨类型
const setRainType = (type) => {
  rainParams.value.type = type
  switch (type) {
    case '毛毛雨':
      setRainIntensity(0.2)
      break
    case '小雨':
      setRainIntensity(0.4)
      break
    case '中雨':
      setRainIntensity(0.6)
      break
    case '大雨':
      setRainIntensity(0.8)
      break
    case '暴雨':
      setRainIntensity(1.0)
      break
    default:
      setRainIntensity(0.5)
  }
}

// 初始化场景
const initScene = () => {
  // 设置相机位置
  camera.value.position.set(0, 10, 20)
  camera.value.lookAt(0, 0, 0)

  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
  scene.value.add(ambientLight)

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
  directionalLight.position.set(10, 20, 15)
  scene.value.add(directionalLight)

  // 创建地面
  const groundGeometry = new THREE.PlaneGeometry(100, 100)
  const groundMaterial = new THREE.MeshStandardMaterial({
    color: 0x333333,
    transparent: true,
    opacity: 0.5
  })
  const ground = new THREE.Mesh(groundGeometry, groundMaterial)
  ground.rotation.x = -Math.PI / 2
  ground.position.y = -10
  scene.value.add(ground)

  // 创建雨滴
  createRain()

  // 添加动画回调
  addAnimationCallback(updateRain)

  // 默认设置为中雨
  setRainType('中雨')

  // 添加GUI控制
  const rainFolder = gui.addFolder('雨滴控制')
  rainFolder.add(rainParams.value, 'type', ['毛毛雨', '小雨', '中雨', '大雨', '暴雨'])
    .name('雨的类型')
    .onChange(setRainType)
  rainFolder.add(rainParams.value, 'intensity', 0, 1, 0.01)
    .name('雨的强度')
    .onChange(setRainIntensity)
  rainFolder.open()
}

onMounted(() => {
  if (containerRef.value) {
    // 初始化场景
    initScene()
  }
})

onUnmounted(() => {
  // 清理资源
  if (rainGeometry) {
    rainGeometry.dispose()
  }
  if (rainParticles && rainParticles.material) {
    rainParticles.material.dispose()
  }
})

// 暴露给外部的方法，用于动态调整雨的效果
defineExpose({
  setRainIntensity,
  setRainType
})
</script>
